package com.iwgang.familiarrecyclerview;

import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

/**
 * Support pull refresh and load more
 * Created by iWgang on 16/04/13.
 * https://github.com/iwgang/FamiliarRecyclerView
 */
public class FamiliarRefreshRecyclerView extends DependentLayout implements Component.TouchEventListener {
    private FamiliarDefaultLoadMoreView mRecycleView;
    private Image                       mIvRefresh;
    private Component                   mIvLoading;
    private DirectionalLayout           mDirectionalLayout;
    private AnimatorProperty            mRefreshAnimator;
    private AnimatorProperty            mLoadingAnimator;
    private VelocityDetector            mVelocityTracker;

    // 记录上一次手指的X坐标
    private float                       mLastX               = 0;

    // 记录上一次手指的Y坐标
    private float                       mLastY               = 0;
    private int                         mFlag                = 0;
    private ListContainer               mListContainer;
    private boolean                     isRefresh;
    private int                         mDataSizes;
    private OnPullRefreshListener       mOnPullRefreshListener;
    private OnLoadMoreListener          mOnLoadMoreListener;
    private boolean                     isPullRefreshEnabled = true;
    private boolean                     isLoadMoreEnabled    = true;
    private Text                        mTvLoading;
    private boolean                     isLoading;

    public FamiliarRefreshRecyclerView(Context context) {
        this(context, null);
    }

    public FamiliarRefreshRecyclerView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public FamiliarRefreshRecyclerView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        setContent(context);
    }

    private void setContent(Context context) {
        LayoutScatter.getInstance(context).parse(
                ResourceTable.Layout_familiar_recycler_layout, this, true);
        Component recycleView = findComponentById(ResourceTable.Id_recycle_view);
        if (recycleView instanceof FamiliarDefaultLoadMoreView) {
            mRecycleView = (FamiliarDefaultLoadMoreView) recycleView;
        }
        Component refresh = findComponentById(ResourceTable.Id_iv_refresh);
        if (refresh instanceof Image) {
            mIvRefresh = (Image) refresh;
        }
        Component load = findComponentById(ResourceTable.Id_iv_loading);
        if (load instanceof Image) {
            mIvLoading = (Image) load;
        }
        Component tvLoad = findComponentById(ResourceTable.Id_tv_load);
        if (tvLoad instanceof Text) {
            mTvLoading = (Text) tvLoad;
        }
        Component layoutImage = findComponentById(ResourceTable.Id_layoutImage);
        if (layoutImage instanceof DirectionalLayout) {
            mDirectionalLayout = (DirectionalLayout) layoutImage;
        }
        mRecycleView.setTouchEventListener(this::onTouchEvent);
        mRefreshAnimator = mIvRefresh.createAnimatorProperty();
        mLoadingAnimator = mIvLoading.createAnimatorProperty();
    }

    private void startRefreshAnimator() {
        mIvRefresh.setVisibility(Component.VISIBLE);
        mRefreshAnimator.setDuration(1000).rotate(360)
                .setLoopedCount(AnimatorProperty.INFINITE).setTarget(mIvRefresh).start();
    }

    private void stopRefreshAnimator() {
        mIvRefresh.setVisibility(Component.HIDE);
        mRefreshAnimator.cancel();
    }

    private void loadingTips() {
        mDirectionalLayout.setVisibility(Component.VISIBLE);
        mIvLoading.setVisibility(HIDE);
        mTvLoading.setText("松开加载更多");
    }

    private void startLoadingAnimator() {
        mDirectionalLayout.setVisibility(Component.VISIBLE);
        mIvLoading.setVisibility(VISIBLE);
        mTvLoading.setText("加载数据中,请稍等...");
        mLoadingAnimator.setDuration(1000).rotate(360)
                .setLoopedCount(AnimatorProperty.INFINITE).setTarget(mIvLoading).start();
    }

    private void stopLoadingAnimator() {
        mDirectionalLayout.setVisibility(Component.HIDE);
        mLoadingAnimator.cancel();
    }

    public void addContentView(Component contentView) {
        if (contentView != null) {
            if (contentView instanceof ListContainer) {
                mListContainer = (ListContainer) contentView;
                mRecycleView.addContentView(mListContainer);
            }
        }
    }

    public void removeContentView(Component contentView) {
        if (contentView != null) {
            mRecycleView.removeContentView(contentView);
        }
    }

    public void setDataSizes(int dataSizes) {
        this.mDataSizes = dataSizes;
    }

    public void setLoadMoreView(Component loadMoreView) {
        if (loadMoreView != null) {
            mIvLoading = loadMoreView;
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent ev) {
        final int action = ev.getAction();
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityDetector.obtainInstance();
        }
        mVelocityTracker.addEvent(ev);
        int sumX = 0;
        int sumY = 0;
        switch (action) {
            // 单指触摸
            case TouchEvent.PRIMARY_POINT_DOWN:
                mLastX = ev.getPointerPosition(ev.getIndex()).getX();
                mLastY = ev.getPointerPosition(ev.getIndex()).getY();
                break;
            // 多指触摸求平均值
            case TouchEvent.OTHER_POINT_DOWN:
                for (int i = 0; i < ev.getPointerCount(); i++) {
                    sumX += ev.getPointerPosition(i).getX();
                    sumY += ev.getPointerPosition(i).getY();
                }
                mLastX = sumX / ev.getPointerCount();
                mLastY = sumY / ev.getPointerCount();
                break;
            // 一根手指抬起求其他手指的平均值
            case TouchEvent.OTHER_POINT_UP:
                int index = ev.getIndex();
                for (int i = 0; i < ev.getPointerCount(); i++) {
                    if (index == i) {
                        continue;
                    }
                    sumX += ev.getPointerPosition(i).getX();
                    sumY += ev.getPointerPosition(i).getY();
                }
                mLastX = sumX / ev.getPointerCount();
                mLastY = sumY / ev.getPointerCount();
                break;
            case TouchEvent.POINT_MOVE:
                // 下拉  offsetY 都>0,上拉  第一次offsetY>0,第二次offsetY<0;
                float currentX = ev.getPointerPosition(ev.getIndex()).getX();
                float currentY = ev.getPointerPosition(ev.getIndex()).getY();
                // 假设向下滑动，此时是正数
                float scrollX = currentX - mLastX;
                float scrollY = currentY - mLastY;
                int offsetY = (int) scrollY;
                int offsetX = (int) scrollX;
                mFlag++;
                if (mFlag == 2) {
                    if (offsetY > 0 && !mListContainer.canScroll(10)) {
                        if (!isRefresh) {
                            if (mListContainer.getItemPosByVisibleIndex(0) != 0) {
                                return false;
                            }
                            isRefresh = true;
                            if (isPullRefreshEnabled) {
                                startRefreshAnimator();
                                if (mOnPullRefreshListener != null) {
                                    mOnPullRefreshListener.onPullRefresh();
                                }
                            }
                        }
                    } else if (offsetY < -1 && !mListContainer.canScroll(-1)) {
                        // 上拉
                        if (!isRefresh) {
                            int lastIndex = mListContainer.getVisibleIndexCount() - 1;
                            if (mListContainer.getItemPosByVisibleIndex(lastIndex) != (mDataSizes - 1)) {
                                return false;
                            }
                            if (isLoadMoreEnabled) {
                                loadingTips();
                                isLoading = true;
                            }
                        }
                    } else {
                        return false;
                    }
                }
                mLastX = currentX;
                mLastY = currentY;
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                // 下拉距离超过头部刷新距离
                if (isLoading && isLoadMoreEnabled) {
                    startLoadingAnimator();
                    if (mOnLoadMoreListener != null) {
                        mOnLoadMoreListener.onLoadMore();
                    }
                }
                new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() {
                    @Override
                    public void run() {
                        isRefresh = false;
                        isLoading = false;
                        mFlag = 0;
                        stopRefreshAnimator();
                        stopLoadingAnimator();
                    }
                }, 1000);
                break;
            case TouchEvent.CANCEL:
                stopRefreshAnimator();
                stopLoadingAnimator();
                isRefresh = false;
                isLoading = false;
                mFlag = 0;
                break;
        }
        return true;
    }

    public void setPullRefreshEnabled(boolean enabled) {
        isPullRefreshEnabled = enabled;
    }

    public void setLoadMoreEnabled(boolean enabled) {
        isLoadMoreEnabled = enabled;
    }

    public void setOnPullRefreshListener(OnPullRefreshListener onPullRefreshListener) {
        this.mOnPullRefreshListener = onPullRefreshListener;
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        this.mOnLoadMoreListener = onLoadMoreListener;
    }

    public interface OnPullRefreshListener {
        void onPullRefresh();
    }

    public interface OnLoadMoreListener {
        void onLoadMore();
    }
}
